package com.freecloud.spring.rebbitmq.utils;

import cn.hutool.core.util.RandomUtil;
import com.freecloud.common.util.SpringContextUtils;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;

/**
 * @Author: maomao
 * @Date: 2019-09-09 11:09
 */
public class RabbitMqUtil {

    /**
     * 消息队列默认前缀
     */
    public final static String RABBIT_MQ_PREFIX = "free.cloud.";

    /**
     * 延迟消息路由名称
     */
    public final static String DELAY_EXCHANGE_NAME = RABBIT_MQ_PREFIX + "delay.exchange";

    /**
     * 死信消息路由名称
     */
    public final static String DIE_EXCHANGE_NAME = RABBIT_MQ_PREFIX + "die.exchange";


    /**
     *  延迟消息队列routingKey
     */
    public final static String DELAY_QUEUE_ROUTING_KEY = ".delay";

    /**
     * 延迟消息转换路由Key
     */
    public final static String DEAD_MESSAGE_ROUTING_KEY = ".dead.message";

    /**
     * 路由Key，包含任意字符
     */
    public final static String ROUTING_KEY_ALL_SUFFIX = ".#";

    private static TopicExchange delayExchange;


    static {
        //创建延迟消息路由（固定一个）
        delayExchange = new TopicExchange(RabbitMqUtil.DELAY_EXCHANGE_NAME);
        RabbitMqUtil.addExchange(delayExchange);
    }

    public static RabbitAdmin getRabbitAdmin(){
        return SpringContextUtils.getBean(RabbitAdmin.class);
    }

    public static RabbitTemplate getRabbitTemplate(){
        return SpringContextUtils.getBean(RabbitTemplate.class);
    }

    /**
     * 创建Exchange
     *
     * @param exchange
     */
    public static void addExchange(AbstractExchange exchange) {
        getRabbitAdmin().declareExchange(exchange);
    }

    /**
     * 创建一个指定的Queue
     *
     * @param queue
     * @return queueName
     */
    public static String addQueue(Queue queue) {
        return getRabbitAdmin().declareQueue(queue);
    }

    /**
     * 绑定一个队列到一个匹配型交换器使用一个routingKey
     * @param queue
     * @param exchange
     * @param routingKey
     */
    public static void addBinding(Queue queue, DirectExchange exchange, String routingKey) {
        Binding binding = BindingBuilder.bind(queue).to(exchange).with(routingKey);
        getRabbitAdmin().declareBinding(binding);
    }
    /**
     * TopicExchange交换绑定
     * @param queue
     * @param exchange
     * @param routingKey
     * @return
     */
    public static void addBinding(Queue queue,TopicExchange exchange,String routingKey){
        Binding binding = BindingBuilder.bind(queue).to(exchange).with(routingKey);
        getRabbitAdmin().declareBinding(binding);
    }

    /**
     * 创建延迟队列，会随指定延迟时间+5秒后删除队列
     * @param queueName
     * @param delayMillis
     * @return
     */
    private static Queue createDelayQueue(String queueName, Integer delayMillis) {
        /**
         * 队列名称  //死信时间 ,死信重新投递的交换机 ,路由到队列的routingKey
         */

        String time = String.valueOf(System.currentTimeMillis());
        String delayQueueName = queueName + ".delay_" + delayMillis + "_" + time;

        return QueueBuilder.durable(delayQueueName)
                //设置消息失效时间
                .withArgument("x-message-ttl",delayMillis * 1000)
                //设置队列自动删除时间 ，比消息延迟时间多5秒
                .withArgument("x-expires", (delayMillis + 5) * 1000)
                //设置死信路由
                .withArgument("x-dead-letter-exchange", RabbitMqUtil.DIE_EXCHANGE_NAME)
                //设置死信路由routingKey
                .withArgument("x-dead-letter-routing-key", queueName + DEAD_MESSAGE_ROUTING_KEY + "." + time)
                .build();
    }

    /**
     * 发送延迟消息
     * @param queueName
     * @param message
     * @param delayMillis
     */
    public static void sendDelayMessage(String queueName,Object message,Integer delayMillis){

        //死信消息队列（动态创建，会销毁）
        Queue delayQueue = createDelayQueue(queueName, delayMillis);
        //创建队列
        addQueue(delayQueue);
        //延迟消息路由Key
        StringBuilder delayRoutingKey = new StringBuilder(queueName + DELAY_QUEUE_ROUTING_KEY);

        delayRoutingKey.append(".").append(message.hashCode() + "_" + RandomUtil.randomString(5));

        //绑定延迟路由
        RabbitMqUtil.addBinding(delayQueue,delayExchange,delayRoutingKey.toString());

        getRabbitTemplate().convertAndSend(RabbitMqUtil.DELAY_EXCHANGE_NAME,delayRoutingKey.toString(),message);
    }

}
